package com.designpatterns.chainofresponsibilitypattern;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InterceptorJDKProxy implements InvocationHandler {

    private Object target;// 真实对象
    private Class interceptorClass;//拦截器全限定名

    public InterceptorJDKProxy() {}
    public InterceptorJDKProxy(Object target, Class interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Class getInterceptorClass() {
        return interceptorClass;
    }

    public void setInterceptorClass(Class interceptorClass) {
        this.interceptorClass = interceptorClass;
    }

    /**
     * 代理逻辑
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 没有设置拦截器则反射原有方法
        if (interceptorClass == null) {
            return method.invoke(target, args);
        }
        Object result = null;
        //如果设置了拦截器则通过反射创建拦截器实例
        Interceptor interceptor = (Interceptor) interceptorClass.newInstance();
        //调用前置方法
        boolean aroundFlag = interceptor.before(proxy, target, method, args);
        //如果前置方法返回false则认为不想执行真实对象的方法，调用around使用around的方法取代真实方法
        if (!aroundFlag) {
            interceptor.repalce(proxy, target, method, args);
        } else {
            result = method.invoke(target, args);
        }
        //调用后置方法
        interceptor.after(proxy, target, method, args);

        return result;
    }

    /**
     * 获取加入拦截器后的代理对象
     * @param target
     * @param interceptorClass
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getProxy(T target, Class interceptorClass) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorJDKProxy(target, interceptorClass));
    }
}
